using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

/*************************************************
 * TODO: TEST THE FUNCTIONS OF THIS CLASS
 *************************************************/

namespace RZEngine2D
{
    public abstract class iListener
    {
        public abstract void HandleEvent(rzEvent Event);
    };

    public struct tClient
    {
        public string szEventID;
        public iListener pOwner;
         
        public tClient(string ID, iListener Owner)
        {
            szEventID = ID;
            pOwner = Owner;
        }

        public tClient(tClient pOther)
        {
            this.szEventID = pOther.szEventID;
            this.pOwner = pOther.pOwner;
        }
    }

    public class rzEvent
    {
        string szEventID;
        Object pData;

        public rzEvent(string EventID, object Data)
        {
            szEventID = EventID;
            pData = Data;
        }

        public string Event
        {
            get { return szEventID; }
        }
        public object Data
        {
            get { return pData; }
        }
    };

    public class rzEventsSystem
    {
        // hold all teh clients that are waiting for events
        Dictionary<string, List<iListener>> ClientBase = new Dictionary<string, List<iListener>>();

        // events going to be processed
        List<rzEvent> CurrentEvents = new List<rzEvent>();

        // functions to find and execute the events on specific objects
        private void DispatchEvent(rzEvent Event)
        {
            // go through all the clients that are signed up for this event
            foreach (iListener ClientData in ClientBase[Event.Event])
            {
                ClientData.HandleEvent(Event);
            }
        }

        bool Registered(string EventID, iListener Client)
        {
            bool Registered = false;

            // check all the clients in the given EventID
            foreach (iListener clientData in ClientBase[EventID])
            {
                if (clientData == Client)
                {
                    Registered = true;
                    break;
                }
            }

            return Registered;
        }
        

        // singleton
        private rzEventsSystem() { }
        private rzEventsSystem(rzEventsSystem es) {}
       
        public static readonly rzEventsSystem instance;
        public static rzEventsSystem Instance
        {
            get { return instance;}
        }

        // the main functions for the system
        public void Register(string EventID, iListener Client)
        {
            // check for valid and non-existing client
            if (Client == null || Registered(EventID, Client))
                return;

            // register the client
            ClientBase[EventID].Add(Client);
        }

        public void UnRegister(string EventID, iListener Client)
        {   
            // go through the list of clients and remove any that are there
            for (int i = 0; i < ClientBase[EventID].Count(); ++i)
            {
                // NOTE: This if check might be redundant
                if (ClientBase[EventID][i] == Client)
                {
                    // remove the object and return
                    ClientBase[EventID].Remove(Client);
                    return;
                }
            }
        }

        public void UnRegisterAll(iListener Client)
        {
            // for each of the events
            foreach (KeyValuePair<string, List<iListener>> Data in ClientBase)
            {
                Data.Value.Clear();
                Data.Key.Remove(0);
            }
            ClientBase.Clear();
        }


        // event-based
        public void Send(string EventID, object Data)
        {
            rzEvent NewEvent = new rzEvent(EventID, Data);
            CurrentEvents.Add(NewEvent);
        }
        
        public void ProcessEvents()
        {
            foreach (rzEvent Event in CurrentEvents)
            {
                DispatchEvent(Event);
            }
            CurrentEvents.Clear();
        }
        
        public void ClearEvents()
        {
            CurrentEvents.Clear();
        }
        

        // unregister Everything
        void ShutdownSystem()
        {
            ClientBase.Clear();
        }
        

    };
}
